///////////////////////////////////////////////////////////////////////
// DiscFormatRawCDEvent.cpp
//
// Wrapper for DDiscFormat2RawCDEvents Interface Events
//
// Written by Nic Wilson
//

#include "stdafx.h"
#include "DiscFormatRawCDEvent.h"

#include "DiscFormatRawCD.h"

// CDiscFormatRawCDEvent

IMPLEMENT_DYNAMIC(CDiscFormatRawCDEvent, CCmdTarget)

BEGIN_INTERFACE_MAP(CDiscFormatRawCDEvent, CCmdTarget)
	INTERFACE_PART(CDiscFormatRawCDEvent, IID_IDispatch, FormatRawCDEvents)
	INTERFACE_PART(CDiscFormatRawCDEvent, IID_DDiscFormat2RawCDEvents, FormatRawCDEvents)
END_INTERFACE_MAP()

CDiscFormatRawCDEvent::CDiscFormatRawCDEvent()
: m_hNotifyWnd(NULL)
, m_ptinfo(NULL)
, m_dwCookie(0)
, m_pUnkSink(0)
, m_pUnkSrc(0)
{
}

CDiscFormatRawCDEvent::~CDiscFormatRawCDEvent()
{
	if (m_dwCookie && (m_pUnkSrc != NULL) && (m_pUnkSink != NULL))
	{
		AfxConnectionUnadvise(m_pUnkSrc, IID_DDiscFormat2RawCDEvents, m_pUnkSink,
			TRUE, m_dwCookie);
	}
}


BEGIN_MESSAGE_MAP(CDiscFormatRawCDEvent, CCmdTarget)
END_MESSAGE_MAP()



// CDiscFormatRawCDEvent message handlers

ULONG FAR EXPORT CDiscFormatRawCDEvent::XFormatRawCDEvents::AddRef()
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)
	return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CDiscFormatRawCDEvent::XFormatRawCDEvents::Release()
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)
	return pThis->ExternalRelease();
}
STDMETHODIMP CDiscFormatRawCDEvent::XFormatRawCDEvents::QueryInterface(REFIID riid,
												   LPVOID FAR* ppvObj)
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)
	return (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj);
}
STDMETHODIMP
CDiscFormatRawCDEvent::XFormatRawCDEvents::GetTypeInfoCount(UINT FAR* pctinfo)
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)
	*pctinfo = 1;
	return NOERROR;
}
STDMETHODIMP CDiscFormatRawCDEvent::XFormatRawCDEvents::GetTypeInfo(
	UINT itinfo,
	LCID lcid,
	ITypeInfo FAR* FAR* pptinfo)
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)
	*pptinfo = NULL;

	if(itinfo != 0)
		return ResultFromScode(DISP_E_BADINDEX);
	pThis->m_ptinfo->AddRef();
	*pptinfo = pThis->m_ptinfo;
	return NOERROR;
}
STDMETHODIMP CDiscFormatRawCDEvent::XFormatRawCDEvents::GetIDsOfNames(
	REFIID riid,
	OLECHAR FAR* FAR* rgszNames,
	UINT cNames,
	LCID lcid,
	DISPID FAR* rgdispid)
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)
	return DispGetIDsOfNames(pThis->m_ptinfo, rgszNames, cNames, rgdispid);
}
STDMETHODIMP CDiscFormatRawCDEvent::XFormatRawCDEvents::Invoke(
	DISPID dispidMember,
	REFIID riid,
	LCID lcid,
	WORD wFlags,
	DISPPARAMS FAR* pdispparams,
	VARIANT FAR* pvarResult,
	EXCEPINFO FAR* pexcepinfo,
	UINT FAR* puArgErr)
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)

	return DispInvoke(&pThis->m_xFormatRawCDEvents, pThis->m_ptinfo,
		dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}


///////////////////////////////////////////////////////////////////////
//
// CDiscFormatRawCDEvent::CreateEventSink
//
// Description:
//			Establishes a link between the CDiscFormatRawCD(IDiscFormat2RawCD)
//			and the CDiscFormatRawCDEvent(DDiscFormat2RawCDEvents) so 
//			CDiscFormatRawCDEvent can receive Update messages
//
CDiscFormatRawCDEvent* CDiscFormatRawCDEvent::CreateEventSink()
{
	// Create the event sink
	CDiscFormatRawCDEvent* pDiscFormatRawCDEvent = new CDiscFormatRawCDEvent();

	pDiscFormatRawCDEvent->EnableAutomation();
	pDiscFormatRawCDEvent->ExternalAddRef();

	return pDiscFormatRawCDEvent;
}

///////////////////////////////////////////////////////////////////////
//
// CDiscFormatRawCDEvent::ConnectDiscFormatRawCD
//
// Description:
//			Establishes a link between the CDiscFormatRawCD(IDiscFormat2RawCD)
//			and the CDiscFormatRawCDEvent(DDiscFormat2RawCDEvents) so 
//			CDiscFormatRawCDEvent can receive Update messages
//
bool CDiscFormatRawCDEvent::ConnectDiscFormatRawCD(CDiscFormatRawCD* pDiscFormatRawCD)
{
	m_pUnkSink = GetIDispatch(FALSE);
	m_pUnkSrc = pDiscFormatRawCD->GetInterface();

	LPTYPELIB ptlib = NULL;
	HRESULT hr = LoadRegTypeLib(LIBID_IMAPILib2, 
		IMAPILib2_MajorVersion, IMAPILib2_MinorVersion, 
		LOCALE_SYSTEM_DEFAULT, &ptlib);
	if (FAILED(hr))
	{
		return false;
	}
	hr = ptlib->GetTypeInfoOfGuid(IID_DDiscFormat2RawCDEvents, &m_ptinfo);
	ptlib->Release();
	if (FAILED(hr))
	{
		return false;
	}

	BOOL bRet = AfxConnectionAdvise(m_pUnkSrc, IID_DDiscFormat2RawCDEvents, m_pUnkSink,
		TRUE, &m_dwCookie);
	if (bRet)
	{
		return true;
	}

	return false;
}


///////////////////////////////////////////////////////////////////////
//
// CDiscFormatRawCDEvent::Update
//
// Description:
//			Receives update notifications from IDiscFormat2RawCD
//
STDMETHODIMP_(HRESULT) CDiscFormatRawCDEvent::XFormatRawCDEvents::Update(IDispatch* objectDispatch, IDispatch* progressDispatch)
{
	METHOD_PROLOGUE(CDiscFormatRawCDEvent, FormatRawCDEvents)

	IDiscFormat2RawCDEventArgs* progress = NULL;
	HRESULT hr = progressDispatch->QueryInterface(IID_PPV_ARGS(&progress));

	IDiscFormat2RawCD* discFormatRawCD = NULL;
	hr = objectDispatch->QueryInterface(IID_PPV_ARGS(&discFormatRawCD));

	IMAPI_FORMAT2_RAW_CD_WRITE_ACTION currentAction = IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_UNKNOWN;
	hr = progress->get_CurrentAction(&currentAction);
	ASSERT(SUCCEEDED(hr));
	if (FAILED(hr))
	{
		return S_OK;
	}

	IMAPI_STATUS imapiStatus = {0};

	if ((currentAction == IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_PREPARING   ) ||
		(currentAction ==  IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_FINISHING))
	{
		progress->get_ElapsedTime(&imapiStatus.elapsedTime);
		progress->get_RemainingTime(&imapiStatus.remainingTime);
	}
	if (currentAction == IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_WRITING)
	{
		progress->get_StartLba(&imapiStatus.startLba);
		progress->get_SectorCount(&imapiStatus.sectorCount);
		progress->get_LastReadLba(&imapiStatus.lastReadLba);
		progress->get_LastWrittenLba(&imapiStatus.lastWrittenLba);
		progress->get_TotalSystemBuffer(&imapiStatus.totalSystemBuffer);
		progress->get_UsedSystemBuffer(&imapiStatus.usedSystemBuffer);
		progress->get_FreeSystemBuffer(&imapiStatus.freeSystemBuffer);
	}

	LRESULT ret = ::SendMessage(pThis->m_hNotifyWnd, WM_IMAPI_RAW_UPDATE, currentAction, (LPARAM)(LPVOID)&imapiStatus);
	if (ret == RETURN_CANCEL_WRITE)
	{
		discFormatRawCD->CancelWrite();
	}

	return S_OK;
}
